{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "tags": [
     "remove-cell"
    ]
   },
   "outputs": [],
   "source": [
    "# Reference: https://jupyterbook.org/interactive/hiding.html\n",
    "# Use {hide, remove}-{input, output, cell} tags to hiding content\n",
    "\n",
    "import sys\n",
    "import os\n",
    "if not any(path.endswith('textbook') for path in sys.path):\n",
    "    sys.path.append(os.path.abspath('../../..'))\n",
    "from textbook_utils import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": [],
    "user_expressions": []
   },
   "source": [
    "(ch:gd)=\n",
    "# Numerical Optimization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "At this point in the book, our modeling procedure should feel familiar:\n",
    "we define a model, choose a loss function, and fit the model by minimizing the\n",
    "average loss over our training data.\n",
    "We've seen several techniques to minimize loss. For example, we used both \n",
    "calculus and a geometric argument in {numref}`Chapter %s <ch:linear>` to\n",
    "find a simple expression for fitting linear models using squared loss."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But empirical loss minimization isn't always so straightforward. Lasso regression, with the addition of the $ L_1 $ penalty to the average squared loss, no longer has a closed form solution, and logistic regression uses cross-entropy loss to fit a nonlinear model. In these cases, we use *numerical optimization* to fit the model, where we systematically choose parameter values to evaluate the average loss in search of the minimizing value.    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When we introduced loss functions in {numref}`Chapter %s <ch:modeling>`, we performed a simple numerical optimization to find the minimizer of the average loss. We created a grid of $ \\theta $ values and evaluated the average loss at all points in the grid (see {numref}`Figure %s <grid-diagram>` for a diagram of this concept). The grid point with the smallest average loss we took as the best fit. Unfortunately, this sort of grid search quickly becomes impractical, for the following reasons:\n",
    "\n",
    "+ For complex models with many features, the grid becomes unwieldy. With only four features and a grid of 100 values for each feature, we must evaluate the average loss at $ 100^4 = 100,000,000 $ grid points.\n",
    "\n",
    "+ The range of parameter values to search over must be specified in advance to create the grid, and when we don't have a good sense of the range, we need to start with a wide grid and possibly repeat the grid search over narrower ranges.\n",
    "\n",
    "+ With a large number of observations, the evaluation of the average loss over the grid points can be slow.  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```{figure} figures/grid-diagram.png\n",
    "---\n",
    "name: grid-diagram\n",
    "---\n",
    "\n",
    "Searching over a grid of points can be computationally slow or inexact\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this chapter, we introduce numerical optimization techniques that take advantage of the shape and smoothness of the loss function in the search for the minimizing parameter values. We first introduce the basic idea behind the technique of gradient descent, then we give an example and describe the properties of the loss function that make gradient descent work, and finally, we provide a few extensions of gradient descent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
